package com.airlines.crewassignment.service.linkline.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.airlines.base.config.datasource.PrimaryDataSourceConfig;
import com.airlines.base.config.response.ResponseResult;
import com.airlines.base.config.response.ResponseResultBuilder;
import com.airlines.common.ListSortUtil;
import com.airlines.common.MD5Util;
import com.airlines.crewassignment.constant.CrewConstant;
import com.airlines.crewassignment.constant.LinkLineConstant;
import com.airlines.crewassignment.constant.PositionConstant;
import com.airlines.crewassignment.dao.PositionMapper;
import com.airlines.crewassignment.domain.Crew;
import com.airlines.crewassignment.domain.FlightInfo;
import com.airlines.crewassignment.domain.LinkLine;
import com.airlines.crewassignment.domain.Position;
import com.airlines.crewassignment.domain.Tech;
import com.airlines.crewassignment.domain.util.FlightDurationUtil;
import com.airlines.crewassignment.service.crew.TechService;
import com.airlines.crewassignment.service.linkline.FullCalendarService;
import com.airlines.crewassignment.service.linkline.LinkLineService;
import com.airlines.crewassignment.service.linkline.PositionService;

/**
 * @author xxxx
 * @date 2018年3月28日 
 * @description
 */
@Service
public class PositionServiceImpl implements PositionService {
	@Autowired
	private TechService techService;
	@Autowired
	private PositionMapper positionMapper;
	@Autowired
	private LinkLineService linkLineService;	
	@Autowired
	private FullCalendarService fullCalendarService;

	@Override
	public Position getPositionPilotBuilder(String acType, Integer serialNo, String rankNo) {
		Tech tech  = null ;
		if(StringUtils.equals(rankNo, CrewConstant.RANK_NO_F_A001) 
				|| StringUtils.equals(rankNo, CrewConstant.RANK_NO_F_B001) ){
			tech = techService.CaptainTechLowestBuilder(acType);
		}else{
			tech = techService.CopilotTechLowestBuilder(acType);
		}
		
		Position position = new Position();
		position.setSerialNo(serialNo);
		position.setDutyCode(CrewConstant.DUTY_F);
		position.setRankNo(rankNo);
		position.setTechLowest(tech); 
		return position;
	}
	
	@Override
	public List<Position> listPositionPilot(LinkLine linkLine) {
		//规则： 
		//如果连线飞行时间<=8小时，则配备机长+副驾
		//如果连线 8小时<飞行时间<=9小时，则配备机长+第一副驾+第二副驾
		//如果连线 9小时<飞行时间<=13小时，则配备 第一机长+第二机长+副驾
		//如果连线 13小时<飞行时间<=17小时，则配备 第一机长+第二机长 + 第一副驾 + 第二副驾
		//如果连线  17小时<飞行时间 ，则不允许分配，这是不允许的
		
		int flyDuration = linkLine.getFlyDuration();
		String acType = linkLine.getAcType();
		
		List<Position> positionList = linkLine.getPositionList();
		
		//第一机长都需要
		Position  p1 = this.getPositionPilotBuilder(acType, 1, CrewConstant.RANK_NO_F_A001);
		positionList.add(p1);
		
		if(flyDuration>0 && flyDuration <= 8*60){
			Position  p2 = this.getPositionPilotBuilder(acType, 2, CrewConstant.RANK_NO_F_C001);
			positionList.add(p2);	
		}else if(flyDuration > 8*60 && flyDuration <= 9*60){
			Position  p2 = this.getPositionPilotBuilder(acType, 2, CrewConstant.RANK_NO_F_C001);
			positionList.add(p2);
			
			Position  p3 = this.getPositionPilotBuilder(acType, 3, CrewConstant.RANK_NO_F_C002);
			positionList.add(p3);
		
		}else if(flyDuration > 9*60 && flyDuration <= 13*60){
			Position  p2 = this.getPositionPilotBuilder(acType, 2, CrewConstant.RANK_NO_F_A001);
			positionList.add(p2);
			
			Position  p3 = this.getPositionPilotBuilder(acType, 3, CrewConstant.RANK_NO_F_C001);
			positionList.add(p3);
		}else if(flyDuration > 13*60 && flyDuration <= 17*60){
			Position  p2 = this.getPositionPilotBuilder(acType, 2, CrewConstant.RANK_NO_F_A001);
			positionList.add(p2);
			
			Position  p3 = this.getPositionPilotBuilder(acType, 3, CrewConstant.RANK_NO_F_C001);
			positionList.add(p3);
			
			Position  p4 = this.getPositionPilotBuilder(acType, 4, CrewConstant.RANK_NO_F_C002);
			positionList.add(p4);
		}
		
		positionKeyInit(positionList);
		
		return positionList;
	}
	
	/**
	 * 号位主键初始化
	 * @param linkLine
	 * @param positionList
	 */
	private  void positionKeyInit(List<Position> positionList){
		for(Position p : positionList){
			this.positionKeyInit(p);
		}
	}
		

	@Override
	public void updatePcodeNull(Date flightDate,String dutyCode) {
		positionMapper.updatePcodeNull(flightDate,dutyCode);
	}

	@Override
	public void updatePcode(Position position, Crew crew) {
		positionMapper.updatePCode(position, crew);
	}

	@Override
	public String positionKeyInit(Position p) {
		Date flightDate = p.getFlightDate();
		Integer crewLinkLineNo = p.getCrewLinkLineNo();
		String dutyCode = p.getDutyCode();
		Integer serialNo = p.getSerialNo();
		return MD5Util.md5Encode(flightDate.toString() + crewLinkLineNo + dutyCode + serialNo);
	}

	@Override
	public Position getByPrimaryKey(int positionId) {
		return positionMapper.selectByPrimaryKey(positionId);
	}

	@Override
	public int saveOrUpdate(Position position) {
		if(!this.updateAbleCheck(position.getFlightDate())){
			return -1;
		}
		Integer positionId = position.getPositionId();
		if(positionId == null){
			return positionMapper.insertSelective(position);
		}else{
			return positionMapper.updateByPrimaryKeySelective(position);
		}
	}

	@Override
	public int deleteByPrimaryKey(int positionId) {
		Position position = this.getByPrimaryKey(positionId);
		if(!this.updateAbleCheck(position.getFlightDate())){
			return -1;
		}
		return positionMapper.deleteByPrimaryKey(positionId);
	}

	@Override
	public int deleteByFlightDate(Date flightDate,Integer crewLinkLineNo, String dutyCode) {
		if(!this.updateAbleCheck(flightDate)){
			return -1;
		}
		return positionMapper.deleteByFlightDate(flightDate,crewLinkLineNo, dutyCode);
	}
	
	/**
	 * 检查是否允许更新、删除、新增操作
	 * @param flightDate
	 * @return
	 */
	@Override
	public boolean updateAbleCheck(Date flightDate){
		DateTime now = DateTime.now().withTimeAtStartOfDay();
		DateTime flightDateTime = new DateTime(flightDate).withTimeAtStartOfDay();
		Duration duration = new Duration(now, flightDateTime);
		long dayDiff  = duration.getStandardDays();
		if(dayDiff>=LinkLineConstant.ABLE_CHANGE_DAY_DIFF){
			return true;
		}else{
			return false;
		}
	}

	@Override
	public List<Position> listPosition(Position position) {
		return positionMapper.listPosition(position);
	}

	@Override
	public int confirm(Date flightDate,String dutyCode) {
		return positionMapper.confirm(flightDate, dutyCode);
	}

	@Transactional(transactionManager = PrimaryDataSourceConfig.TRANSACTION_MANAGER)
	@Override
	public int saveAutoAssign(List<Position> list, String dutyCode) {
		int count = 0;
		for(Position p :list){
			p.setAutoFlag(PositionConstant.AUTO_FLAG_A);
			p.setConfirmFlag(PositionConstant.CONFIRM_FLAG_N);
			p.setDutyCode(dutyCode);
			p.setStatus(PositionConstant.STATUS_A);
			int i = positionMapper.updateByPrimaryKeySelective(p);
			count += i ;
		}
		return count;
	}

	@Override
	public List<Position> listPositionByCrewType(int crewTypeId) {
		return positionMapper.listPositionByCrewType(crewTypeId) ;
	}

	@Transactional(transactionManager = PrimaryDataSourceConfig.TRANSACTION_MANAGER)
	@Override
	public void initPositionByCrewType(String dutyCode ,Date flightDate, Integer crewLinkLineNo, int crewTypeId) {
		//删除原先数据库中存在的号位
		Position deleteQuery = new Position();
		deleteQuery.setFlightDate(flightDate);
		deleteQuery.setCrewLinkLineNo(crewLinkLineNo);
		deleteQuery.setDutyCode(dutyCode);
		List<Position> deleteList = this.listPosition(deleteQuery);
		for(Position p : deleteList){
			this.deleteByPrimaryKey(p.getPositionId());
		}
		
		
		
		LinkLine linkLine= linkLineService.getLinkLine(flightDate, crewLinkLineNo, dutyCode);		
		List<Position> positionList = this.listPositionByCrewType(crewTypeId);
		for(Position p : positionList){
			
			p.setFlightDate(linkLine.getFlightDate());
			p.setCrewLinkLineNo(linkLine.getCrewLinkLineNo());
			p.setFlyHours(linkLine.getFlyHours());
			p.setAutoFlag(PositionConstant.AUTO_FLAG_A);
			p.setConfirmFlag(PositionConstant.CONFIRM_FLAG_N);
			p.setStatus(PositionConstant.STATUS_A);

			
			
			//防止数据库中该连线已经存在号位
			Position query = new Position();
			query.setFlightDate(p.getFlightDate());
			query.setCrewLinkLineNo(p.getCrewLinkLineNo());
			query.setSerialNo(p.getSerialNo());
			query.setDutyCode(p.getDutyCode());
			List<Position> inDbList = this.listPosition(query);
		
			//boolean hasPcode = false;
			if(inDbList !=null && inDbList.size()>0){
				p.setPositionId(inDbList.get(0).getPositionId());
				//如果号位已经存在，则删除
				for(Position indb : inDbList){
//					if(StringUtils.isNotBlank(indb.getPCode())){
//						hasPcode = true;
//					}
					this.deleteByPrimaryKey(indb.getPositionId());
				}
			}
			
//			if(!hasPcode){
//				p.setPCode("");
//				this.saveOrUpdate(p);
//			}
			
			this.saveOrUpdate(p);
		}
	}

	@Override
	public int buildCrewTypeIdByLinkLine(String dutyCode, Date flightDate, Integer crewLinkLineNo) {
		//LinkLine linkLine= linkLineService.getLinkLine(flightDate, crewLinkLineNo, dutyCode);
		//1.查询同一个连线同一天内下相同任务环的航班列表
		List<FlightInfo> flightInfoList = fullCalendarService.listFlightBySameTaskLoopFactSameFlightDate(dutyCode, flightDate, crewLinkLineNo);
		if(CollectionUtils.isEmpty(flightInfoList)){
			return -1;
		}
		int flightDurationSum = FlightDurationUtil.getFlightDuration(flightInfoList);
		
		ListSortUtil.sort(flightInfoList, true, "std");
		FlightInfo fristFlightInfo = flightInfoList.get(0); 
		DateTime start = new DateTime(fristFlightInfo.getStd()).minusMinutes(LinkLineConstant.DUTY_DURATION_ADD_START);//报到时间
		boolean startIsMorning = false;
		boolean startIsNight  = false;
		if(start.getHourOfDay()<=4){
			startIsMorning = true;
		}
		if(start.getHourOfDay()>=20){
			startIsNight = true;
		}
		
		
		if(StringUtils.equals(dutyCode, CrewConstant.DUTY_F)){
			/*
			 *  2名驾驶员报到时间在00:00-04:59或20:00-23:59，最大飞行时间8小时
				2名驾驶员报到时间在05:00-19:59，最大飞行时间9小时
				3名驾驶员最大飞行时间13小时（双机长）
				4名驾驶员最大飞行时间17小时（两套组）
			if(flightDurationSum>13*60 && flightDurationSum <=17*60){
				return PositionConstant.CREW_TYPE_ID_2; //两套组！！？！？？！？！？
			}
			if(flightDurationSum>9*60 && flightDurationSum <=13*60){
				return PositionConstant.CREW_TYPE_ID_26; //双机长！！？！？？！？！？
			}else{
				return PositionConstant.CREW_TYPE_ID_8; //普通三人制
			} */
			
			/*
				3.如果报到时间为早晚航班，且飞行时间超8小时，则必须配备双机长。
				4.如果报到时间为早晚航班，且飞行时间超13小时，则必须配备两套组。
				5.如果报到时间不是早晚航班，且飞行时间超过9小时，则必须配备双机长。
				6.如果报到时间不是早晚航班，且飞行时间超13小时，则必须配备两套组。
			 */
//			if(startIsMorning || startIsNight){
//				if(flightDurationSum>13*60){
//					return PositionConstant.CREW_TYPE_ID_2; //两套组
//				}else if(flightDurationSum >8*60){
//					return PositionConstant.CREW_TYPE_ID_26;//双机长
//				}else{
//					return PositionConstant.CREW_TYPE_ID_8; //普通三人制
//				}
//			}else{
//				if(flightDurationSum>13*60){
//					return PositionConstant.CREW_TYPE_ID_2; //两套组
//				}else if(flightDurationSum >9*60){
//					return PositionConstant.CREW_TYPE_ID_26;//双机长
//				}else{
//					return PositionConstant.CREW_TYPE_ID_8; //普通三人制
//				}
//			}
			if(flightDurationSum<=8*60 && (startIsMorning || startIsNight)){
				return PositionConstant.CREW_TYPE_ID_8; //普通三人制
			}else if(flightDurationSum<=9*60 && !startIsMorning && !startIsMorning){
				return PositionConstant.CREW_TYPE_ID_8; //普通三人制
			}else if(flightDurationSum<=13*60){
				return PositionConstant.CREW_TYPE_ID_26;//双机长 
			}else if(flightDurationSum <= 17*60){
				return PositionConstant.CREW_TYPE_ID_2; //两套组
			}else{
				return -1;
			}
			
			
			
		}

		if(StringUtils.equals(dutyCode, CrewConstant.DUTY_C)){
			return PositionConstant.CREW_TYPE_ID_38;
		}
		if(StringUtils.equals(dutyCode, CrewConstant.DUTY_A)){
			return PositionConstant.CREW_TYPE_ID_6;
		}
		return 0;
	}

	@Override
	public int getNewSerialNo(List<Integer> serialNoHaveList) {
		if(CollectionUtils.isEmpty(serialNoHaveList)){
			return 1;
		}
		
		Collections.sort(serialNoHaveList);
		int max = serialNoHaveList.get(serialNoHaveList.size()-1);
		List<Integer> allList = new ArrayList<>();
		for(int i = 1; i<= max+1 ;i++){
			allList.add(i);
		}
		
		for(Integer i : allList){
			boolean flag = false;
			for(Integer serialNo : serialNoHaveList){
				if(i.equals(serialNo)){
					flag = true;
				}
			}
			if(!flag){
				return i;
			}
		}
		return max+1;
	}

	@Override
	public boolean isDoubleCaption(List<Position> positonList) {
		int captionCount = 0;

		return false;
	}

	@Override
	public boolean isDoubleGroup(List<Position> positonList) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public ResponseResult<String> initPositon(String dutyCode, Date flightDateStart, Date flightDateEnd) {
		DateTime start = new DateTime(flightDateStart);
		DateTime end = new DateTime(flightDateEnd);
		for(DateTime temp = start; !temp.isAfter(end) ;temp = temp.plusDays(1)){
			Date flightDate = temp.toDate();
			List<LinkLine> linkLineList =  linkLineService.listLinkLineBase(dutyCode, flightDate);
			for(LinkLine l : linkLineList){
				int  crewType = this.buildCrewTypeIdByLinkLine(dutyCode, temp.toDate(), l.getCrewLinkLineNo());
				this.initPositionByCrewType(dutyCode, flightDate, l.getCrewLinkLineNo(), crewType);
			}
		}
		return ResponseResultBuilder.successResult();
	}
	
	

}
